Clobber = {}
Clobber.config = {}
Clobber.backdrop = {}

local function printhelp(...)
	if select('#',...)>0 then
		return tostring((...)), printhelp(select(2,...))
	end
end

local function print(...)
	ChatFrame1:AddMessage('Clobber: '..strjoin(',',printhelp(...)))
end

local layout
local _, class = UnitClass("player");
if ((class == "ROGUE")or(class == "DRUID")) then
	layout = "cp"
elseif class == "DEATHKNIGHT" then
	layout = "dk"
else
	layout = nil
end

local gtg = nil
local useEH = nil
local EventHandler
	
local time = GetTime()
local TTL, tTTL = 0.05, 0.10
local TSLU, tTSLU = 0, 0

local frame = CreateFrame('Frame','ClobberFrame',UIParent)
local text = frame:CreateFontString(nil,'OVERLAY')
local combo = frame:CreateFontString(nil,'OVERLAY')

local r = {}
for i=1,6 do
	r[i] = frame:CreateFontString(nil,'OVERLAY')
end

local function EventHandler(self, event, ...)
	local f = self[event]
	if f then 
		f(self,...) 
	end 
end

local function Round(num,idp)
  if idp and idp>0 then
    local mult = 10^idp
    return math.floor(num * mult + 0.5) / mult
  end
  return math.floor(num + 0.5)
end

local function Clobber_CheckEH()
	if IsAddOnLoaded("EventHorizon") then
		useEH = true
	else
		useEH = nil
	end
end

local function Clobber_EnterVehicle(unit)
	if unit == "player" then
		if (CanExitVehicle() and UnitPower("vehicle")) then
			layout = "veh"
		end
	else return end
end

local function Clobber_ExitVehicle(unit)
	if ((unit == "player") and (layout == "veh")) then
		if ((class == "ROGUE")or(class == "DRUID")) then
			layout = "cp"
		elseif class == "DEATHKNIGHT" then
			layout = "dk"
		else
			layout = nil
		end
	else return end
end

local function Clobber_UpdateCP()
	local c
	if layout == "cp" then
		c = GetComboPoints("player")
	elseif layout == "veh" then
		c = GetComboPoints("vehicle")
	end
	combo:SetText(c)
	combo:SetVertexColor(unpack(Clobber.color["c"..c]))
end

local function Clobber_UpdateRune(runeid,usable)
	local start,duration,ready = GetRuneCooldown(runeid)
	local rC = Clobber.config.runeCountdown or 0
	
	if runeid > 6 then return else
		if ready == true then	
			r[runeid]:SetText(Clobber.config.runeReady)
		else
			local cd = start + duration - GetTime()
			cd = Round(cd)
			if ((rC > 0) and (cd <= rC)) then
				r[runeid]:SetText(cd)
			else
				r[runeid]:SetText(Clobber.config.runeCooling)
			end			
		end
	end
end

local function Clobber_UpdateRuneType(runeid)
	local rt = GetRuneType(runeid)
	local rc = Clobber.color
	if runeid > 6 then return else
		r[runeid]:SetVertexColor(unpack(rc["r"..rt]))
	end
	Clobber_UpdateRune(runeid)
end	

local function Clobber_SpawnStyleFrame()
	local st = Clobber.backdrop
	local sf = CreateFrame('Frame','ClobberBG',ClobberFrame)
	
	sf:SetFrameStrata('BACKGROUND')
	if st.backdrop then
		if useEH then
			local eh = EventHorizon.config
			if eh.backdrop == true then
				sf:SetPoint('TOPRIGHT', ClobberFrame, 'TOPRIGHT', eh.padding, eh.padding)
				sf:SetPoint('BOTTOMLEFT', ClobberFrame, 'BOTTOMLEFT', -eh.padding, -eh.padding)
				sf:SetBackdrop({
					bgFile = eh.bg,
					edgeFile = eh.border, tileSize = 0, edgeSize = eh.edgesize,
					insets = eh.inset,
				})
				sf:SetBackdropColor(unpack(eh.bgcolor))
				sf:SetBackdropBorderColor(unpack(eh.bordercolor))
			else return end
		else
			sf:SetPoint('TOPRIGHT', ClobberFrame, 'TOPRIGHT', st.padding, st.padding)
			sf:SetPoint('BOTTOMLEFT', ClobberFrame, 'BOTTOMLEFT', -st.padding, -st.padding)
			sf:SetBackdrop({
				bgFile = st.bgFile,
				edgeFile = st.borderFile, tileSize = 0, edgeSize = st.edgesize,
				insets = st.inset,
			})
			sf:SetBackdropColor(unpack(st.bgColor))
			sf:SetBackdropBorderColor(unpack(st.borderColor))
		end
	end	
end

local function Clobber_ApplyFonts(fs,j,rune)		-- Ex: ApplyFonts(fontstring1,"LEFT")
	if rune then
		fs:SetFont(Clobber.config.runeFont,Clobber.config.runeFontSize)
	else
		fs:SetFont(Clobber.config.font,Clobber.config.fontSize)
	end
	fs:SetJustifyH(j)
	fs:SetHeight(Clobber.config.height)
	fs:Show()
end

local function Clobber_ApplyConfig()
	if useEH then
		local eh = EventHorizon.config
	end
	local cc = Clobber.config
	local offset = cc.offset
	
	frame:SetHeight(cc.height)
	
	if not useEH then
		frame:SetPoint(unpack(cc.point))
		frame:SetWidth(cc.width)
	elseif cc.position == 'top' then
		frame:SetPoint("BOTTOMLEFT", EventHorizon.mainframe, "TOPLEFT", 0, offset)
		frame:SetPoint("BOTTOMRIGHT", EventHorizon.mainframe, "TOPRIGHT", 0, offset)
	elseif cc.position == 'bottom' then
		frame:SetPoint("TOPLEFT", EventHorizon.mainframe, "BOTTOMLEFT", 0, -offset)
		frame:SetPoint("TOPRIGHT", EventHorizon.mainframe, "BOTTOMRIGHT", 0, -offset)
	else
		frame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
		print("WARNING! You have an invalid position set in your config or myconfig.lua file!")
	end
	
	local toffx = cc.textOffset[1]
	local toffy = cc.textOffset[2]
	
	if ((layout == "cp") or (layout == "veh")) then
		combo:SetPoint("LEFT", ClobberFrame, "LEFT", toffx, toffy)
		text:SetPoint("LEFT", combo, "RIGHT", 10, 0)
	elseif layout == "dk" then
		local rs = Clobber.config.runeSpacing
		text:SetPoint("RIGHT", ClobberFrame, "RIGHT", -toffx, toffy)
		combo:Hide()
		for i=1,6 do
			if i == 1 then
				r[1]:SetPoint("LEFT", ClobberFrame, "LEFT", toffx, cc.runeOffset)
			else
				r[i]:SetPoint("LEFT", r[i-1], "LEFT", cc.runeSpacing, 0)
			end
		end
	else
		text:SetPoint("LEFT", ClobberFrame, "LEFT", toffx, toffy)
		combo:Hide()
	end
	
	Clobber_SpawnStyleFrame()
end

local function Clobber_Init()	
	if layout == "dk" then
		combo:Hide()
		Clobber_ApplyFonts(text,"RIGHT")		
		for i=1,6 do
			Clobber_ApplyFonts(r[i],"LEFT",true)
			r[i]:Show()
		end
	else
		Clobber_ApplyFonts(text,"LEFT")
		if layout == "cp" then
			Clobber_ApplyFonts(combo,"LEFT")
			combo:Show()
			for i=1,6 do
				r[i]:Hide()
			end
		end
		if layout == "veh" then
			combo:Show()
			Clobber_ApplyFonts(combo,"RIGHT")
			for i=1,6 do
				r[i]:Hide()
			end
		end
	end

	if layout == "cp" then
		Clobber_UpdateCP()
	elseif layout == "dk" then
		for i=1,6 do
			Clobber_UpdateRuneType(i)
		end
	elseif layout == "veh" then
		Clobber_UpdateCP()
	end

	Clobber_ApplyConfig()
	frame:Show()
end

local function Clobber_Update()
	local p,pm,pt,pts
	if layout == "veh" then
		p = UnitPower("vehicle")
		pm = UnitPowerMax("vehicle")
		pt, pts = UnitPowerType("vehicle")
	else
		p = UnitPower("player")
		pm = UnitPowerMax("player")
		pt, pts = UnitPowerType("player")
	end
	local c = Clobber.color[pts]
	local m = Clobber.color.fade
	
	if p and pt then
		if(((pt == 1) or (pt == 6)) and(p == 0)) then
			text:SetVertexColor(c[1]*m,c[2]*m,c[3]*m)
		else
			text:SetVertexColor(c[1],c[2],c[3])
		end
		if((pt == 0)or(pt == 3)) then
			if p == pm then
				text:SetVertexColor(c[1]*m,c[2]*m,c[3]*m)
			else
				text:SetVertexColor(c[1],c[2],c[3])
			end
		end
	end

text:SetText(p)
TSLU = 0
end

local function Clobber_ThrottledUpdate()
	if layout == "dk" then
		local rC = Clobber.config.runeCountdown or 0
		if (rC > 0) then
			for i=1,6 do
				Clobber_UpdateRuneType(i)
			end
		end
	end
tTSLU = 0
end

local function Clobber_OnUpdate(self,elapsed)		-- DON'T TOUCH ME!
	if not gtg then return else
	TSLU = TSLU + elapsed
	tTSLU = tTSLU + elapsed
		while (TSLU > TTL) do
			Clobber_Update()
			TSLU = TSLU - TTL
		end
		while (tTSLU > tTTL) do
			Clobber_ThrottledUpdate()
			tTSLU = tTSLU - tTTL
		end
	end
end

frame:SetScript("OnUpdate", Clobber_OnUpdate)
frame:SetScript("OnEvent", EventHandler)

do
	local talentcheck = GetTalentInfo(1,1)
	if talentcheck then
		-- Talent information is already available, which means that the interface was reloaded.
		frame:RegisterEvent('PLAYER_LOGIN')
		function frame:PLAYER_LOGIN()
			Clobber_CheckEH()
			Clobber_Init()
			self:UnregisterEvent('PLAYER_LOGIN')
			gtg = true
				if layout == "dk" then
					for i=1,6 do
					Clobber_UpdateRuneType(i)
					end
				end
		end
	else
		frame:RegisterEvent('PLAYER_ALIVE')
		function frame:PLAYER_ALIVE()
			Clobber_CheckEH()
			Clobber_Init()
			self:UnregisterEvent('PLAYER_ALIVE')
			gtg = true
		end
	end
end

frame:RegisterEvent('UNIT_ENTERED_VEHICLE')
frame:RegisterEvent('UNIT_EXITED_VEHICLE')
function frame:UNIT_ENTERED_VEHICLE(unit)
	frame:RegisterEvent('UNIT_COMBO_POINTS')
	frame:RegisterEvent('PLAYER_TARGET_CHANGED')
	Clobber_EnterVehicle(unit)
	Clobber_Init()
end
function frame:UNIT_EXITED_VEHICLE(unit)
	frame:UnregisterEvent('UNIT_COMBO_POINTS')
	frame:UnregisterEvent('PLAYER_TARGET_CHANGED')
	Clobber_ExitVehicle(unit)
	Clobber_Init()
end

if layout == "cp" then
	frame:RegisterEvent('UNIT_COMBO_POINTS')
	frame:RegisterEvent('PLAYER_TARGET_CHANGED')
	
	function frame:UNIT_COMBO_POINTS()
		Clobber_UpdateCP()
	end
	function frame:PLAYER_TARGET_CHANGED()
		Clobber_UpdateCP()
	end
end

if layout == "dk" then
	frame:RegisterEvent('RUNE_POWER_UPDATE')
	frame:RegisterEvent('RUNE_TYPE_UPDATE')
	
	function frame:RUNE_POWER_UPDATE(runeid,usable)
		Clobber_UpdateRune(runeid,usable)
	end
	function frame:RUNE_TYPE_UPDATE(runeid)
		Clobber_UpdateRuneType(runeid)
	end
end
